package com.zm.common.utils.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * http工具包
 *
 * @Author: 汪焰
 * @Date: 2020/6/16 23:20
 * @Version: 1.0.0
 **/
@Slf4j
public class HttpUtils {

//        <!--http-->
//        <dependency>
//            <groupId>org.apache.httpcomponents</groupId>
//            <artifactId>httpclient</artifactId>
//            <version>4.5.12</version>
//        </dependency>
    
    private static String EMPTY = "";
    private static Integer ZERO = 0;
    private static Integer ONE = 1;


    private static PoolingHttpClientConnectionManager pool;
    private static RequestConfig config;
    /*utf-8字符编码*/
    public static final String CHARSET_UTF8 = "utf8";
    /*HTTP内容类型*/
    public static final String CONTENT_TYPE_TEXT_HTML = "text/xml";
    /*HTTP内容类型。相当于form表单的形式，提交数据 */
    public static final String CONTENT_TYPE_FORM_URL = "application/x-www-form-urlencoded";
    /*HTTP内容类型。相当于body中json字符串，提交数据 */
    public static final String CONTENT_TYPE_JSON_URL = "application/json";

    static {
        pool = new PoolingHttpClientConnectionManager();
        //设置最大连接数
        pool.setMaxTotal(100);
        //设置每个主机的最大连接数
        pool.setDefaultMaxPerRoute(10);
        //设置请求信息
        config = RequestConfig.custom()
                /*创建连接的最长时间*/
                .setConnectTimeout(1000)
                /*获取连接的最长时间*/
                .setConnectionRequestTimeout(500)
                /*数据传输的最长时间*/
                .setSocketTimeout(10000)
                .build();
    }

    /**
     * get请求
     */
    public static String get(String url) {
        return get(url, null, null);
    }

    public static String get(String url, Map<String, Object> params) {
        return get(url, null, params);
    }

    public static String get(String url, Map<String, Object> heads, Map<String, Object> params) {
        url = url + "?" + mapToParams(params);
        HttpGet httpGet = getHttpGet(url);
        addHeaders(httpGet, heads);
        return send(httpGet);
    }

    public static String getSSL(String url) {
        return getSSL(url, null, null);
    }

    public static String getSSL(String url, Map<String, Object> params) {
        return getSSL(url, null, params);
    }

    public static String getSSL(String url, Map<String, Object> heads, Map<String, Object> params) {
        url = url + "?" + mapToParams(params);
        HttpGet httpGet = getHttpGet(url);
        addHeaders(httpGet, heads);
        return sendSSL(httpGet);
    }

    /**
     * post请求
     */

    public static String postForm(String url, Map<String, Object> formData) {
        return postForm(url, null, formData);
    }

    public static String postForm(String url, Map<String, Object> header, Map<String, Object> formData) {
        String params = mapToParams(formData);
        HttpPost httpPost = getHttpPost(url);
        addHeaders(httpPost, header);
        StringEntity entity = new StringEntity(params, ContentType.create(CONTENT_TYPE_FORM_URL, CHARSET_UTF8));
        httpPost.setEntity(entity);
        return send(httpPost);
    }

    public static String postJson(String url, String jsonData) {
        return postJson(url, null, jsonData);
    }

    public static String postJson(String url, Map<String, Object> header, String jsonData) {
        HttpPost httpPost = getHttpPost(url);
        addHeaders(httpPost, header);
        StringEntity entity = new StringEntity(jsonData, ContentType.create(CONTENT_TYPE_JSON_URL, CHARSET_UTF8));
        httpPost.setEntity(entity);
        return send(httpPost);
    }

    public static String postJsonSSL(String url, String jsonData) {
        return postJsonSSL(url, null, jsonData);
    }

    public static String postJsonSSL(String url, Map<String, Object> header, String jsonData) {
        HttpPost httpPost = getHttpPost(url);
        addHeaders(httpPost, header);
        StringEntity entity = new StringEntity(jsonData, ContentType.create(CONTENT_TYPE_JSON_URL, CHARSET_UTF8));
        httpPost.setEntity(entity);
        return sendSSL(httpPost);
    }

    /**
     * 底层工具
     */

    private static HttpGet getHttpGet(String url) {
        return new HttpGet(url);
    }

    private static HttpPost getHttpPost(String url) {
        return new HttpPost(url);
    }

    private static HttpPut getHttpPut(String url) {
        return new HttpPut(url);
    }

    private static HttpDelete getHttpDelete(String url) {
        return new HttpDelete(url);
    }

    private static String send(HttpRequestBase request) {
        CloseableHttpResponse response = null;
        try {
            log.info("httpUtils request url : {}", request.getURI());
            log.info("httpUtils request Method : {}", request.getMethod());

            CloseableHttpClient httpClient = HttpClients.custom()
                    /*设置连接池管理*/
                    .setConnectionManager(pool)
                    /*设置请求配置*/
                    .setDefaultRequestConfig(config)
                    .build();
            //使用httpClient 发送请求，获取响应
            response = httpClient.execute(request);
            return parse(response);
        } catch (IOException e) {
        } finally {
            //关闭response
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

    private static String sendSSL(HttpRequestBase request) {
        CloseableHttpResponse response = null;
        try {
            log.info("httpUtils request url : {}", request.getURI());
            log.info("httpUtils request Method : {}", request.getMethod());

            CloseableHttpClient httpClient = createSSLHttpClient();
            //使用httpClient 发送请求，获取响应
            response = httpClient.execute(request);
            return parse(response);
        } catch (IOException e) {
        } finally {
            //关闭response
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

    private static CloseableHttpClient createSSLHttpClient() {
        try {
            SSLContext context = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE);
            return HttpClients.custom().setSSLSocketFactory(factory).build();
        } catch (Exception e) {
            log.error("build createSSLHttpClient error! {}", e);
        }
        return null;
    }

    public static String parse(CloseableHttpResponse response) {
        String result = null;
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            HttpEntity entity = response.getEntity();
            if (statusCode >= HttpStatus.OK.value() && statusCode < HttpStatus.MULTIPLE_CHOICES.value()) {
                result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                log.error("\n -----接口失败 code:{} \n -----接口失败 message:{}", statusCode, entity);
                result = EMPTY;
            }
        } catch (Exception e) {
            log.error("\n 解析接口响应数据 出现异常:{}", e);
        } finally {
            try {
                response.close();
            } catch (Exception e) {
            }
        }
        return result;
    }

    private static HttpRequestBase addHeaders(HttpRequestBase request, Map<String, Object> heads) {
        if (heads == null || heads.size() < ONE) {
            return request;
        }
        for (Map.Entry<String, Object> head : heads.entrySet()) {
            request.addHeader(head.getKey(), String.valueOf(head.getValue()));
        }
        return request;
    }

    private static String mapToParams(Map<String, Object> params) {
        if (params == null || params.size() < ONE) {
            return EMPTY;
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();

            if (key == null || key.length() < ONE) {
                continue;
            }
            String value = String.valueOf(entry.getValue());
            if (value == null || value.length() < ONE) {
                continue;
            }
            sb.append(key).append("=").append(value).append("&");
        }
        sb.deleteCharAt(sb.length() - ONE);
        String result = sb.toString();
        sb.setLength(ZERO);
        return result;
    }

}